#include "demo5.h"

// uint8_t buf[256] = {0};
// uint16_t len     = 0; // 使用len的bit15位，用于做一个状态量，标识，是否已经完成接收

// uint16_t usart_brr(uint32_t bound)
// {
//     // 72M的情况下
//     float div     = 72000000UL / bound / 16.0f;
//     uint32_t divM = (uint32_t)div;
//     float divF    = div - divM; // 完整的数-整数部分，就是小数部分

//     // 需要设置到BRR中的小数部分的时候，是x16
//     divF = divF * 16;
//     // 需要将小数部分，转化成最靠近这个小数的整数
//     uint32_t tmp = (uint32_t)divF;
//     if ((divF - tmp) >= 0.5) {
//         tmp += 1;
//     }

//     return (uint16_t)((divM << 4) | (tmp << 0));
// }

// static void usart1_init(void)
// {
//     // 先开时钟
//     __HAL_RCC_GPIOA_CLK_ENABLE();
//     __HAL_RCC_USART1_CLK_ENABLE();
//     __HAL_RCC_AFIO_CLK_ENABLE();

//     {
//         // 当外设使用到GPIO的时候，需要将GPIO开启复用功能
//         // 将对应的GPIO开启复用功能
//         GPIOA->CRH |= 0x03 << 4;    // 11：输出模式，最大速度50MHz
//         GPIOA->CRH &= ~(0x03 << 6); // 先清掉CNF9
//         GPIOA->CRH |= 0x02 << 6;    // 10：复用功能推挽输出模式
//     }
//     {
//         // USART1的RX的GPIO初始化
//         GPIOA->CRH &= ~(0x03 << 8);  // 00：输入模式(复位后的状态)
//         GPIOA->CRH &= ~(0x03 << 10); // 先清掉CNF10
//         GPIOA->CRH |= 0x02 << 10;    // 10：复用功能推挽输出模式
//         GPIOA->ODR |= 1 << 10;       // 建议默认设置为上拉模式
//     }

//     // 如果想发送数据，需要使用波特率发生器进行驱动（时钟源USART1是来自于APB2）
//     USART1->BRR = usart_brr(115200);
//     // 无校验，停止位
//     // 是否选择使用校验（是需要先决定是8bit还是9bit）
//     USART1->CR1 &= ~(1 << 12);
//     USART1->CR1 &= ~(1 << 10); // 不使用硬件校验(PS，就无效了)

//     USART1->CR2 &= ~(0x03 << 12); // 停止位

//     {
//         USART1->CR1 |= 1 << 3; // 使能TE位
//     }

//     {
//         USART1->CR1 |= 1 << 2; // RE：接收使能 (Receiver enable)
//     }

//     USART1->CR1 |= 1 << 13; // 开启USART1，UE位

//     // 开启中断
//     USART1->CR1 |= 1 << 5; // 开启接收完成中断
//     USART1->CR1 |= 1 << 4; // 开启空闲中断

//     // 配置NVIC
//     NVIC_SetPriority(USART1_IRQn, 2);
//     NVIC_EnableIRQ(USART1_IRQn);
// }

// /**
//  * USART1的全局中断处理函数
//  */
// void USART1_IRQHandler(void)
// {
//     if ((USART1->SR & (1 << 5)) != 0x00) { // 接收成功了数据
//         buf[len] = USART1->DR;
//         len++;
//     }

//     if ((USART1->SR & (1 << 4)) != 0x00) { // 可以通过总线空闲，判断数据帧是否发送完成
//         USART1->DR;                        // 读取一下
//         // 接收完成，将len的最高位，设置为1
//         len |= 1 << 15;
//     }
// }

// void usart1_tx(uint8_t *buf, uint16_t len)
// {
//     uint16_t i = 0; // 由新旧版本的编译器决定的
//     for (i = 0; i < len; i++) {

//         // 只有在发送寄存器为空的时候，才可以设置DR寄存器
//         while ((USART1->SR & (1 << 7)) == 0x00)
//             ;

//         USART1->DR = buf[i];
//     }

//     // 非常重要！！！
//     while ((USART1->SR & (1 << 6)) == 0x00)
//         ;

//     // while (len) {
//     //     USART1->DR = *buf;
//     //     while ((USART1->SR & (1 << 6)) == 0x00)
//     //         ;
//     //     buf++;
//     //     len--;
//     // }
// }

// void demo5_test(void)
// {
//     usart1_init();

//     while (1) {

//         // 可以循环发送数据
//         // HAL_Delay(1000);
//         // usart1_tx("HelloWorld123", 13);

//         // // 接收数据
//         // if ((USART1->SR & (1 << 5)) != 0x00) { // 接收成功了数据
//         //     buf[len] = USART1->DR;
//         //     len++;
//         // }

//         // if ((USART1->SR & (1 << 4)) != 0x00) { // 可以通过总线空闲，判断数据帧是否发送完成
//         //     USART1->DR;                        // 读取一下

//         //     // 将数据返回给上位机
//         //     usart1_tx(buf, len);
//         //     len = 0; // 发完之后，清除len
//         // }

//         if ((len & (1 << 15)) != 0x00) {
//             len &= ~(1 << 15); // 清除接收完成标识

//             usart1_tx(buf, len);
//             len = 0; // 发完之后，清除len
//         }

//         HAL_Delay(20);
//         // 就可以做其他的任务了
//     }
// }

// // 接收的数据长度
// #define USART1_RX_SIZE 256 // 最大可接受的数据长度

// uint16_t len                = 0;
// uint8_t buf[USART1_RX_SIZE] = {0};

// UART_HandleTypeDef huart1;
// extern void Error_Handler(void);

// static void _usart1_rx_callback(struct __UART_HandleTypeDef *huart, uint16_t Pos)
// {
//     if (huart->Instance == USART1) {
//         len = Pos; // 本次接收的实际数据长度是多少

//         // 需要在再次开启接收
//         HAL_UARTEx_ReceiveToIdle_IT(huart, buf, USART1_RX_SIZE);
//     }
// }

// static void usart1_init(uint32_t bound)
// {
//     __HAL_RCC_USART1_CLK_ENABLE();
//     __HAL_RCC_GPIOA_CLK_ENABLE();
//     __HAL_RCC_AFIO_CLK_ENABLE(); // 复用功能的时钟

//     {
//         GPIO_InitTypeDef GPIO_InitStruct = {0};
//         /**USART1 GPIO Configuration
//             PA9     ------> USART1_TX
//             PA10     ------> USART1_RX
//         */
//         GPIO_InitStruct.Pin   = GPIO_PIN_9; // PA9，复用输出模式
//         GPIO_InitStruct.Mode  = GPIO_MODE_AF_PP;
//         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

//         GPIO_InitStruct.Pin  = GPIO_PIN_10; // PA10,输入模式，
//         GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//         GPIO_InitStruct.Pull = GPIO_NOPULL; // 浮空输入（推荐上拉或者浮空）
//         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//     }

//     huart1.Instance          = USART1;               // 实例对象 USART1
//     huart1.Init.BaudRate     = bound;                // 波特率
//     huart1.Init.WordLength   = UART_WORDLENGTH_8B;   // 数据位宽度
//     huart1.Init.StopBits     = UART_STOPBITS_1;      // 停止位
//     huart1.Init.Parity       = UART_PARITY_NONE;     // 是否使用校验位
//     huart1.Init.Mode         = UART_MODE_TX_RX;      // 同时支持数据接收和发送
//     huart1.Init.HwFlowCtl    = UART_HWCONTROL_NONE;  // 是否使用硬件控制流
//     huart1.Init.OverSampling = UART_OVERSAMPLING_16; // 溢出 不用
//     if (HAL_UART_Init(&huart1) != HAL_OK) {
//         Error_Handler();
//     }

//     // 开启NVIC
//     HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
//     HAL_NVIC_EnableIRQ(USART1_IRQn);

//     // 注册接收完成回调函数
//     HAL_UART_RegisterRxEventCallback(&huart1, _usart1_rx_callback);
//     // HAL_UART_RegisterCallback

//     // 开启接收中断（开启接收到空闲中断）
//     HAL_UARTEx_ReceiveToIdle_IT(&huart1, buf, USART1_RX_SIZE); // 这个函数，只会成功接收一次，
// }

// /**
//  * @brief This function handles USART1 global interrupt.
//  */
// void USART1_IRQHandler(void)
// {
//     HAL_UART_IRQHandler(&huart1);
// }

// #include <stdio.h>
// #include "printf.h" //直接使用printf.c的源码文件
// #include <string.h>
// #include <stdio.h>

#include "usart1.h"

extern uint16_t u1RxLen;
extern uint8_t u1RxBuf[USART1_RX_SIZE];

void demo5_test(void)
{
    int i = 0;
    // char str[20] = {0};

    usart1_init(115200);

    printf("HelloWorld");

    while (1) {

        // if (len != 0) { // 如果接收的数据长度不是0，就说明有数据
        //     if (HAL_UART_Transmit(&huart1, buf, len, 0xFFF) != HAL_OK) {
        //         Error_Handler();
        //     }

        //     len = 0; // 一定要让len还原
        // }

        // HAL_Delay(1000);
        // // printf("i = %f\r\n", i); // 使用printf.c源码，可以很好的实现float类型的输出
        // i += 1;

        // // 还会有人使用sprintf，先拼接字符串，然后在发送
        // sprintf(str, "i = %d\r\n", i); // 很多时候，标准库为了节约flash空间，会压缩一些标准库，所以float的输出，可能是不行的
        // HAL_UART_Transmit(&huart1, (uint8_t *)str, strlen(str), 0xFFF);

        if (u1RxLen != 0) { // 如果接收的数据长度不是0，就说明有数据
            usart1_tx(u1RxBuf, u1RxLen);

            u1RxLen = 0; // 一定要让len还原
        }

        HAL_Delay(1000);
        printf("i = %d\r\n", i); // 使用printf.c源码，可以很好的实现float类型的输出
        i += 1;
    }
}

// // 如果是MDK的话，可以使用fputc重写这个函数，实现printf重定向
// // 在GCC中，不是用重写fputc的方法，实现重定向
// int fputc(int ch, FILE *f)
// {
//     // 只有在发送寄存器为空的时候，才可以设置DR寄存器
//     while ((USART1->SR & (1 << 7)) == 0x00)
//         ;

//     USART1->DR = ch;

//     // 非常重要！！！
//     while ((USART1->SR & (1 << 6)) == 0x00)
//         ;

//     return ch;
// }

// // 很多人，说是重写这个函数，显现gcc下的pritf
// // 在vscode 的GNU下的编译器，使用这个方式是行不通的
// int _write(int file, char *ptr, int len)
// {
//     int i = 0;
//     for (i = 0; i < len; i++) {
//         // 只有在发送寄存器为空的时候，才可以设置DR寄存器
//         while ((USART1->SR & (1 << 7)) == 0x00)
//             ;
//         USART1->DR = ptr[i];
//     }

//     // 非常重要！！！
//     while ((USART1->SR & (1 << 6)) == 0x00)
//         ;

//     return len;
// }

// 当发现以上另种方式，无法正常工作的时候，推荐使用printf.c源码进行
// #include "printf.h"

// void _putchars(char *buf, short len)
// {

//     // 将来，如果使用DMA的方式，可以极大提高发送效率
//     int i = 0;
//     for (i = 0; i < len; i++) {
//         // 只有在发送寄存器为空的时候，才可以设置DR寄存器
//         while ((USART1->SR & (1 << 7)) == 0x00)
//             ;
//         USART1->DR = buf[i];
//     }

//     // 非常重要！！！
//     while ((USART1->SR & (1 << 6)) == 0x00)
//         ;
// }